# 默认参数 的大坑
def add_end(L=[]):
    L.append('END')
    return L


l1 = add_end([1, 2, 3])
print(l1)

# 这里 会 出现和预想不一样的结果

# Python函数在定义的时候，默认参数L的值就被计算出来了，即[]，
# 因为默认参数L也是一个变量，它指向对象[]，每次调用该函数，
# 如果改变了L的内容，则下次调用时，默认参数的内容就变了，
# 不再是函数定义时的[]了。
print(add_end())
print(add_end())
print(add_end())
# 定义默认参数要牢记一点：默认参数必须指向不变对象！
"""
['END']
['END', 'END']
['END', 'END', 'END']

"""


def add_end2(L=None):
    if L is None:
        L = []
    L.append('END')
    return L


print(add_end2())
print(add_end2())
print(add_end2())
"""
['END']
['END']
['END']
"""


# *nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用，而且很常见。


def fact(n):
    if n == 1:
        return 1
    return n * fact(n - 1)


print(fact(1))
print(fact(30))
print(fact(50))


# 尾递归是指，在函数返回的时候，调用自身本身，并且，return语句不能包含表达式。
# 这样，编译器或者解释器就可以把尾递归做优化，使递归本身无论调用多少次，
# 都只占用一个栈帧，不会出现栈溢出的情况。


def fact1(n):
    return fact_iter(n, 1)


def fact_iter(num, product):
    if num == 1:
        return product
    return fact_iter(num - 1, num * product)


print(fact1(100))
print(fact1(4))
# 遗憾的是，大多数编程语言没有针对尾递归做优化，
# Python解释器也没有做优化，所以，即使把上面的fact(n)
# 函数改成尾递归方式，也会导致栈溢出。

print('*' * 50)
print('*' * 50)
print('*' * 50)


# 利用递归函数移动汉诺塔:
def move(n, a, b, c):
    if n == 1:
        print('move', a, '-->', c)
    else:
        move(n - 1, a, c, b)
        move(1, a, b, c)
        move(n - 1, b, a, c)


move(4, 'A', 'B', 'C')

print('@' * 90)

aa01 = 'ABCDEFG'[:3]
print(aa01)

d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}

for key in d:
    print(key)
    print(d[key])

for value in d.values():
    print(value)

for k, v in d.items():
    print(k, v)


